﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Threading;

namespace Boomerang.Common.Tracing
{
    public class BoomerangFileTraceListener : TextWriterTraceListener
    {
        private static NumberedStream mStream;
        const string FileQuotaAttribute = "maxFileSizeKB";
        const string IncludeDateTimeAttribute = "includeDateTime";
        const long DefaultMaxQuota = 4000;
        bool MaxQuotaInitialized;

        public BoomerangFileTraceListener(string file)
            : base(mStream = new NumberedStream(file))
        {
        }

        public BoomerangFileTraceListener()
            : base(mStream = new NumberedStream("boomerang.log"))
        {
        }

        public override void WriteLine(string message)
        {
            base.WriteLine(PrefixMessage(message));
        }

        public override void Write(string message)
        {
            base.Write(PrefixMessage(message));
        }

        public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args)
        {
            DetermineOverQuota();
            WriteLine(string.Format(CultureInfo.InvariantCulture," {0} - {1} ", eventType, string.Format(CultureInfo.InvariantCulture,format, args)));
        }

        public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message)
        {
            DetermineOverQuota();
            WriteLine(CultureInfo.InvariantCulture,string.Format(CultureInfo.InvariantCulture," {0} - {1} ", eventType, message));
        }

        public static string PrefixMessage(string message)
        {
            StackTrace stackTrace = new StackTrace();
            StackFrame frame = stackTrace.GetFrame(0);
            string source = new string('.', stackTrace.FrameCount) + String.Format(CultureInfo.InvariantCulture,"{0} [{1}] {2}", frame.GetMethod().DeclaringType, Thread.CurrentThread.ManagedThreadId.GetHashCode(), frame.GetMethod().Name);

            DateTime timeStamp = DateTime.Now;
            return String.Format(CultureInfo.InvariantCulture, "{0}.{1:000}|{2}|{3}", timeStamp.ToString("yyyyMMdd_HH:mm:ss", CultureInfo.InvariantCulture), timeStamp.Millisecond, source, message);
        }

        private long MaxQuotaSize
        {
            //Get the MaxQuotaSize from configuration file
            //Set to Default Value if there are any problems

            get
            {
                long MaxFileQuota = 0;
                if (!this.MaxQuotaInitialized)
                {
                    try
                    {
                        string MaxQuotaOption = this.Attributes[BoomerangFileTraceListener.FileQuotaAttribute];
                        if (MaxQuotaOption == null)
                        {
                            MaxFileQuota = DefaultMaxQuota;
                        }
                        else
                        {
                            MaxFileQuota = int.Parse(MaxQuotaOption, CultureInfo.InvariantCulture);
                        }
                    }
                    catch (Exception)
                    {
                        MaxFileQuota = DefaultMaxQuota;
                    }
                    finally
                    {
                        this.MaxQuotaInitialized = true;
                    }
                }

                if (MaxFileQuota <= 0)
                {
                    MaxFileQuota = DefaultMaxQuota;
                }

                //MaxFileQuota is in KB in the configuration file, convert to bytes

                MaxFileQuota = MaxFileQuota * 1024;
                return MaxFileQuota;
            }
        }

        private void DetermineOverQuota()
        {

            //Set the MaxQuota on the stream if it hasn't been done

            if (!this.MaxQuotaInitialized)
            {
                mStream.MaxQuotaSize = this.MaxQuotaSize;
            }

            //If we're past the Quota, flush, then switch files

            if (mStream.IsOverQuota)
            {
                base.Flush();
                mStream.SwitchFiles();
            }
        }
    }
}
